package com.tianji.learning.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.tianji.api.client.user.UserClient;
import com.tianji.api.dto.user.UserDTO;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.DateUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.constants.RedisConstants;
import com.tianji.learning.pojo.po.PointsBoard;
import com.tianji.learning.mapper.PointsBoardMapper;
import com.tianji.learning.pojo.vo.PointsBoardItemVO;
import com.tianji.learning.pojo.vo.PointsBoardVO;
import com.tianji.learning.query.PointsBoardQuery;
import com.tianji.learning.service.IPointsBoardService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.BoundZSetOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static com.tianji.learning.constants.LearningConstants.POINTS_BOARD_TABLE_PREFIX;

/**
 * <p>
 * 学霸天梯榜 服务实现类
 * </p>
 *
 * @author author
 * @since 2023-11-10
 */
@Service
@RequiredArgsConstructor
public class PointsBoardServiceImpl extends ServiceImpl<PointsBoardMapper, PointsBoard> implements IPointsBoardService {

    private final StringRedisTemplate redisTemplate;
    private final UserClient userClient;

    /**
     * 分页查询指定赛季的积分排行榜
     *
     * @param query
     * @return
     */
    @Override
    public PointsBoardVO queryPointsBoardBySeason(PointsBoardQuery query) {
        // 判断是否查询的当前赛季
        Long season = query.getSeason();
        boolean isCurrent = season == null || season == 0;

        // 获取Redis的key
        LocalDateTime now = LocalDateTime.now();
        String key = RedisConstants.POINT_BOARD_KEY_PREFIX + now.format(DateUtils.POINTS_BOARD_SUFFIX_FORMATTER);

        // 查询我的积分和排名
        PointsBoard myBoard = isCurrent ?
                queryMyCurrentBoard(key) : // 当前赛季直接从redis查询
                queryMyHistoryBoard(season); // 从数据库查询历史赛季信息

        // 查询榜单列表
        List<PointsBoard> pointsBoardList = isCurrent ?
                queryCurrentBoardList(key, query.getPageNo(), query.getPageSize()) :
                queryHistoryBoardList(query);

        // VO封装
        PointsBoardVO vo = new PointsBoardVO();
        // 处理我的信息
        if (myBoard != null) {
            vo.setRank(myBoard.getRank());
            vo.setPoints(myBoard.getPoints());
        }
        if (CollUtils.isEmpty(pointsBoardList)) {
            return vo;
        }

        // 查询用户信息
        Set<Long> userIds = pointsBoardList.stream().map(PointsBoard::getUserId).collect(Collectors.toSet());
        List<UserDTO> userDTOS = userClient.queryUserByIds(userIds);
        Map<Long, String> userDTOMaps = new HashMap<>(userIds.size());
        if (CollUtils.isNotEmpty(userDTOS)) {
            userDTOMaps = userDTOS.stream().collect(Collectors.toMap(UserDTO::getId, UserDTO::getName));
        }

        // 转换vo
        List<PointsBoardItemVO> items = new ArrayList<>(pointsBoardList.size());
        for (PointsBoard pointsBoard : pointsBoardList) {
            PointsBoardItemVO pbVO = new PointsBoardItemVO();
            pbVO.setName(userDTOMaps.get(pointsBoard.getUserId()));
            pbVO.setPoints(pointsBoard.getPoints());
            pbVO.setRank(pointsBoard.getRank());
            items.add(pbVO);
        }

        vo.setBoardList(items);
        return vo;
    }

    private PointsBoard queryMyHistoryBoard(Long season) {
        return null;
    }

    private PointsBoard queryMyCurrentBoard(String key) {
        // 绑定redis  key
        BoundZSetOperations<String, String> operations = redisTemplate.boundZSetOps(key);

        // 查询积分和排名
        Double score = operations.score(UserContext.getUser().toString());
        Long rank = operations.reverseRank(UserContext.getUser().toString());

        PointsBoard p = new PointsBoard();
        p.setPoints(score == null ? 0 : score.intValue());
        p.setRank(rank == null ? 0 : rank.intValue() + 1);
        return p;
    }

    @Override
    public List<PointsBoard> queryHistoryBoardList(PointsBoardQuery query) {

        return null;

    }
    @Override
    public List<PointsBoard> queryCurrentBoardList(String key, Integer pageNo, Integer pageSize) {
        // 计算ZSet分页
        int from = (pageNo - 1) * pageSize;

        // ZSet的分页查询
        Set<ZSetOperations.TypedTuple<String>> typedTuples = redisTemplate.opsForZSet()
                .reverseRangeWithScores(key, from, from + pageSize - 1);

        if (CollUtil.isEmpty(typedTuples)) {
            return CollUtils.emptyList();
        }

        int rank = from + 1;
        List<PointsBoard> list = new ArrayList<>(typedTuples.size());
        for (ZSetOperations.TypedTuple<String> tuple : typedTuples) {
            String userId = tuple.getValue();
            Double points = tuple.getScore();
            if (ObjectUtil.hasNull(userId, points)) {
                continue;
            }

            PointsBoard pointsBoard = new PointsBoard();
            pointsBoard.setUserId(Long.valueOf(userId));
            pointsBoard.setPoints(points.intValue());
            pointsBoard.setRank(rank++);
            list.add(pointsBoard);
        }

        return list;
    }

    @Override
    public void createPointBoardTable(Integer season) {
        getBaseMapper().createPointBoardTable(POINTS_BOARD_TABLE_PREFIX + season);
    }
}
